package com.hyjx.framework.orm.dao;

import com.hyjx.framework.common.CommonUtil;
import com.hyjx.framework.common.Constants;
import com.hyjx.framework.common.util.ReflectUtil;
import com.hyjx.framework.common.util.SpringBeanUtil;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 数据操作层基础对象
 *
 * @author
 */
@Repository
public class BaseDao extends SqlSessionDaoSupport implements IBaseDao {
    private static Logger logger = LoggerFactory.getLogger(BaseDao.class);
    
    @Override
    @Autowired
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        super.setSqlSessionFactory(sqlSessionFactory);
    }
    
    
    /**
     * 添加数据对象
     */
    
    @Override
    public boolean addObject(String sqlid, Object obj) {
        logger.debug("==>  Insert Sql Id:" + sqlid);
        this.getSqlSession().insert(sqlid, obj);
        return true;
    }
    
    @Override
    public int updateObject(String sqlid, Object obj) {
        logger.debug("==>  Update Sql Id:" + sqlid);
        return this.getSqlSession().update(sqlid, obj);
    }
    
    @Override
    public int deleteObject(String sqlid, Object obj) {
        logger.debug("==>  Delete Sql Id:" + sqlid);
        return this.getSqlSession().delete(sqlid, obj);
    }
    
    @Override
    public Object queryObject(String sqlid, Object obj) {
        logger.debug("==>  Query Sql Id:" + sqlid);
        return this.getSqlSession().selectOne(sqlid, obj);
    }
    
    @Override
    @SuppressWarnings("rawtypes")
    public List queryObjectList(String sqlid, Object obj) {
        logger.debug("==>  Query Sql Id:" + sqlid);
        return this.getSqlSession().selectList(sqlid, obj);
    }
    
    @Override
    public String getCurrSql(Object params, String sqlName) {
        StringBuffer sb = new StringBuffer();
        BoundSql boundSql = getSqlSession().getConfiguration().getMappedStatement(sqlName).getSqlSource().getBoundSql(params);

        String sqlString = boundSql.getSql();
        if (params != null && !"".equals(params)) {
            List sqlParam = boundSql.getParameterMappings();
            if (sqlString.indexOf("?") > -1) {
                String[] sqlfrag = sqlString.split("\\?");
                if (params instanceof List){
                    for (Object param : (List)params){
                        sb.append(getSqlFromParam(sqlfrag, param, sqlParam));
                    }
                } else {
                    sb = getSqlFromParam(sqlfrag, params, sqlParam);
                }
                
            }
        
            return sb.toString();
        } else {
            return sqlString.toString();
        }
    }
    
    private StringBuffer getSqlFromParam(String[] sqlfrag, Object param, List sqlParam){
        StringBuffer sb = new StringBuffer();
        
        for(int i = 0; i < sqlParam.size(); ++i) {
            sb.append(sqlfrag[i]);
            Object p = ReflectUtil.getFieldValue(param, ((ParameterMapping) (sqlParam).get(i)).getProperty());
            if (p == null){
                sb.append(p);
            } else {
                sb.append("'").append(p).append("'");
            }
        }
        return sb;
    }
    
    /**
     * 通过sqlID进行分页查询操作返回json对象
     *
     * @param sqlID
     * @param countSqlID
     * @param paramObject
     * @return json对象
     */
    @Override
    public String getPageJsonStr(final String sqlID, final String countSqlID, Object paramObject) {
        String pageNo = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getParameter("page");
        String pageSize = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getParameter("rows");
        
        Pager pager = null;
        pageNo = pageNo == null ? "" + Constants.PageNo : pageNo;
        pageSize = pageSize == null ? Constants.PageSize + "" : pageSize;
        int iPageNo = Integer.parseInt(pageNo);
        int iPageSize = Integer.parseInt(pageSize);
        pager = getPager(sqlID, countSqlID, paramObject, iPageNo, iPageSize);
        StringBuffer sb = new StringBuffer();
        sb.append("{");
        sb.append("\"total\": " + pager.getRowCount() + ",");
        sb.append("\"rows\": ");
        sb.append(CommonUtil.getJsonString(pager.getResultList()).toString());
        sb.append("}");
        return sb.toString();
    }
    
    /**
     * 获取查询json格式数据，针对手动分页情况。
     *
     * @param sqlID       sql语句id
     * @param countSqlID  查询数量语句id
     * @param paramObject 参数对象
     * @param pageNo      页码
     * @param pageSize    页数
     * @return 返回json格式数据
     */
    @Override
    public String getPageJsonStr(final String sqlID, final String countSqlID, Object paramObject, int pageNo, int pageSize) {
        Pager pager = null;
        pager = getPager(sqlID, countSqlID, paramObject, pageNo, pageSize);
        StringBuffer sb = new StringBuffer();
        sb.append("{");
        sb.append("\"total\": " + pager.getRowCount() + ",");
        sb.append("\"rows\": ");
        sb.append(CommonUtil.getJsonString(pager.getResultList()).toString());
        sb.append("}");
        return sb.toString();
    }
    
    @Override
    @SuppressWarnings("rawtypes")
    public List queryObjectList(String sqlid) {
        return getSqlSession().selectList(sqlid);
    }
    
    /**
     * 得到查询列表对象
     *
     * @param sqlID
     * @param countSqlID
     * @param paramObject
     * @return
     */
    @Override
    public Pager getPager(final String sqlID, final String countSqlID,
                          final Object paramObject) {
        String pageNo = null;
        String pageSize = null;
        
        pageNo = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getParameter("page");
        pageSize = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getParameter("rows");
        pageNo = pageNo == null ? Constants.PageNo + "" : pageNo;
        pageSize = pageSize == null ? Constants.PageSize + "" : pageSize;
        int int_no = Integer.parseInt(pageNo);
        int int_size = Integer.parseInt(pageSize);
        return getPager(sqlID, countSqlID, paramObject, int_no, int_size);
    }
    
    /**
     * 获取当前数据库的连接
     *
     * @return
     */
    @Override
    public Connection getCurrentConnection() {
        return getSqlSession().getConnection();
    }
    
    /**
     * 通过sql执行查询操作返回列表对象
     *
     * @param sql
     * @return
     */
    @Override
    public List<Map<String, Object>> queryListBySql(String sql) {
        JdbcTemplate jt = SpringBeanUtil.getBean("jdbcTemplate", JdbcTemplate.class);
        return jt.queryForList(sql);
    }
    
    /**
     * 执行sql操作
     *
     * @param sql
     * @return
     */
    @Override
    public boolean executeSql(String sql) {
        try {
            JdbcTemplate jt = SpringBeanUtil.getBean("jdbcTemplate", JdbcTemplate.class);
            jt.execute(sql);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
    
    /**
     * 执行批量插入，返回影响行数。
     */
    @Override
    public int batchInsertObject(String sqlid, List<?> list) {
        logger.debug("==>  Batch Insert Sql Id:" + sqlid);
        int effectRows = 0;
        SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) SpringBeanUtil.getBean("sqlSessionFactory");
        SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
        try {
            for (Object obj : list) {
                effectRows += session.insert(sqlid, obj);
            }
            session.commit();
            session.clearCache();
        } catch (Exception e) {
            session.rollback();
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            session.close();
        }
        return effectRows;
    }
    
    /**
     * 批量更新操作，返回影响行数。
     */
    @Override
    public int batchUpdateObject(String sqlid, List<?> list) {
        logger.debug("==>  Batch Update Sql Id:" + sqlid);
        int effectRows = 0;
        
        SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) SpringBeanUtil.getBean("sqlSessionFactory");
        SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
        try {
            for (Object obj : list) {
                effectRows += session.update(sqlid, obj);
            }
            session.commit();
            session.clearCache();
        } catch (Exception e) {
            session.rollback();
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            session.close();
        }
        return effectRows;
    }
    
    /*得到pager，为了改pager里面的属性的值*/
    @Override
    public Pager getPageList(final String sqlID, final String countSqlID, Object paramObject) {
        String pageNo = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getParameter("page");
        String pageSize = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getParameter("rows");
        Pager pager = null;
        pageNo = pageNo == null ? "" + Constants.PageNo : pageNo;
        pageSize = pageSize == null ? Constants.PageSize + "" : pageSize;
        int iPageNo = Integer.parseInt(pageNo);
        int iPageSize = Integer.parseInt(pageSize);
        pager = getPager(sqlID, countSqlID, paramObject, iPageNo, iPageSize);
        return pager;
    }
    
    /**
     * 通过当前页数、每页显示条数得到分页对象
     *
     * @param sqlID
     * @param countSqlID
     * @param paramObject
     * @param iPageNo
     * @param iPageSize
     * @return
     */
    @Override
    public Pager getPager(final String sqlID, final String countSqlID,
                          final Object paramObject, final int iPageNo, final int iPageSize) {
        return getPager(sqlID, countSqlID, 0, paramObject, iPageNo, iPageSize, false);
    }
    
    /**
     * 通过sqlID进行分页查询操作返回pager对象
     *
     * @param sqlID
     * @param countSqlID
     * @param iRowCount
     * @param paramObject
     * @param iPageNo
     * @param iPageSize
     * @param useCache
     * @return
     */
    @SuppressWarnings("rawtypes")
    private Pager getPager(final String sqlID, final String countSqlID, final int iRowCount, final Object paramObject,
                           final int iPageNo, final int iPageSize, final boolean useCache) {
        if (logger.isDebugEnabled()) {
            logger.debug("==>\tcountSqlID: " + countSqlID);
        }
        
        int totalNum = 0;
        if (useCache) {
            totalNum = iRowCount;
        } else {
            String countValue = getSqlSession().selectOne(countSqlID, paramObject);
            try {
                if (countValue != null) {
                    totalNum = Integer.parseInt(countValue);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        int pageNo = iPageNo;
        int pageSize = iPageSize;
        if (pageSize < 1) {
            pageSize = Constants.PageSize;
        }
        if (pageNo < 1) {
            pageNo = Constants.PageNo;
        } else if (pageNo - 1 > totalNum / pageSize) {
            pageNo = totalNum / pageSize + 1;
        }
    
        if (logger.isDebugEnabled()) {
            logger.debug("==>\tsqlID: " + sqlID);
        }
        
        List list = getSqlSession().selectList(sqlID, paramObject, new RowBounds((iPageNo - 1) * pageSize, pageSize));
        if (list == null) {
            list = new ArrayList();
        }
        Pager pager = new Pager(pageSize, pageNo, totalNum, list);
        pager.setSql(sqlID);
        pager.setCountSql(countSqlID);
        pager.setCondition(paramObject);
        return pager;
    }
    
    
}